package eth

import (
	"bytes"
	"encoding/json"
	"math/big"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"

	"github.com/ethereum-optimism/optimism/op-service/bigs"
)

// Example account result taken from the Goerli SystemConfig proxy:
// cast proof 0xAe851f927Ee40dE99aaBb7461C00f9622ab91d60 0x65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08 --block 8481106
// The provided slot is the unsafe block signer.
const resultData = `
{
  "address": "0xae851f927ee40de99aabb7461c00f9622ab91d60",
  "balance": "0x0",
  "codeHash": "0x1f958654ab06a152993e7a0ae7b6dbb0d4b19265cc9337b8789fe1353bd9dc35",
  "nonce": "0x1",
  "storageHash": "0x88219055c2fef8800e02f071d053a86a4194e70a81b6e45f1fecca7dae0432da",
  "accountProof": [
    "0xf90211a063a66cd84a54f8ee248662f1d4637936c430a0f455eeec8c01ee56db898dddfba0be9003fb3e36a55cfea1eda010c0a459f10729db9809e0bd1e3599f46c5ffed1a0a08d018d3cf38b0d0cbff14288699705dfa7cf27dc20fbbaae9351837eff4751a0eed877086740a930f035b75ebb26ce63df0f61baea52bf05f4c7421014debf33a053ea34e49423e790b10d9a36f498f337b3f079ed611d98a3f8550c34212dcbd7a0c370d5b874f70b9fd1c8a2fe98b0ef60c480fbe00566a7d5a5e682d9859398f2a0da820e94aac0b444a8dcfebc7dc9ec942f04f252da25b10faf50b57f969aa1f5a0413e8039c67d8acbe20993ab364c2c477d1ce85e8ae723c33acd506175ce4bffa0f70e5d5d934c53b2302ec3f98bd3f33f39a15fabb8c32e5e7acc97121d7a9cf3a0b41e7073ae943e498681b5d86941401c29b38c93fa347ace6bb15ba74ccbf45ea0a3b0aa548cac9cbbfcfabd980c1ceae8bdc39ad2682fc6e6d9cf0f4bdb273884a04d7932870a3d25163ea28ae5ebe702b841d755541d2af98c5c1c08090327fab1a06e41c3fb6362dd860a098aacf13a81c9d26e9b822c1066ca76cb98607f3e257aa0079ffe59ddb21ccd03bcbf1cc42fc0fb89dcae93ffeed9b82a848828199ab057a0dce67e92c8991df57ecac2237244d12e92f6514db1c5f076718fe40266bbf741a08dd7d3b3b041889f837217761b4e87510428ea41b3aff4e5725fd8efc2d735b980",
    "0xf90211a0809683f3310d75dff5eb95296aa9ff5d74fbde9f873b9a6b245513887f9c6e91a055450f5338cc2f8f4306912e938df3fe490929614604eeea4c03581b98c8ae8ea04e50b57da8fc16a5d5460892196631737eeb1cc1e995e5c1de9c381ed1fb84d4a07d65e61a50579d689422446c23df10c4c0b5ec41239a910ca86634e2fee75320a091c77e1f72302bdb3985b249dba07d1abaa345296080c369bd84c518669297e1a019a185bedc83ab48c51dffe4c58ab88e30c88976a3b059ab524ef7ab42886d61a0a6c249e070db991141ee1289a5ed212f81673f8cd3f7bf35c27c335cc77d3eeca0c7d7a7f5036c8c3185cd0ca231775047192419b8f7e7b5a462c8e713ab2f4fcda006084fdd6777d076850defc5c6f1336535bbc2ec95a0e3f91fc5ac9761aee770a0c85a82f527990667217fac36ebfb9f4af29a6ff7b0b3d41cdcb256a26ca5f621a06a382d1f5a9bb0b712c89e82b0aaf26cf7c5984255377fd7428457d390330d40a0194f1f730e71559662ea2d9bdc681761eaf54decc7041766b5d7b7e8086d2480a05afe23c9ec57c22d9639f9228aa389e7a70a4e1e3e675856792f4a92fe284478a05bcacd2d3d2ac267d5b0367b56f05e4c808e2a5ecd04a10f1399e313fd41b273a09e62b6f5b7b77a1657ded9f0bef2af7fee11f2bf0518a5cceb5ceae2845c16f0a06d0ee25c5a3acd2b8d3253b856a77187b76f90d60b2356fc77f6e79766410cc580",
    "0xf90211a0a6b81aae9b8aff6ac275885f6dfa4bc11949e3e8cbfad05714c3233303fa83f5a0e29595c647574b219c3068a768d47347b0e8a272da881aeb4525af051faab847a0441c1549c250c0c1bc0fa1b73e9f9ac9998b5dcef65a57ecd3f748ce02be4251a0353bd042ac0cf9a90a9cc02cc131f5d58f531df8df7ab752f6caa9b6807a506ea07340f489ba55fc8cfde61384c4990f74034f0bc0c7e1d68733284cb5c30d5bbea00ff5d4191ef973be9ae73b3fd9d01f52b54aafa20f147b6a5ca6b9e56a1f9ec4a0e167cd5a249a0dc2afbb9b2aafbd3b6e0160739a99e482d22d722c78fa296772a004202f2695770715d36e9aad418cc005fd8b22b927f1e1383b4e95ca18f41f61a0be38b6340286e0cd2454d90d8ed2f7e26bce5b7774f8adfa8f54a75bc4635d18a0cacc635e487a0d7dd19373bcd0a32e4cea0655f93d61f2940a6063059a044bf7a0bcd8f9ab88356e86cea7cd27454525ade016bccf26f414ad9fa93e0280d40df4a0d5651902739f9dfaff0f1178ea7cba617087234dd0e2895424961fad98605a27a0f76890befb5b3b20695d64b6a7c416709c93032012b46245c5bc00dd104b84f3a00ff372b11e0fb8febd467e060f7ce126e705a07a203a3f6dd93c7e3f36f4608ea0b4ea8133548c9b9d8f62b86aa703f65e3323a92a4b4711f80a734b80814b0825a04db29c4cb760e4831bfe40cdb0f554d74e98da26715c7e6319317c8c9a9c247580",
    "0xf90211a026ffcc82ed6e3cd13ea30ed185afae29eed7f7fbde7f46010061791b5441b7dfa086b3018a2c001ffd6cc76e58372c49f5a2ba42335789fdcea878d93ceeeeb969a0589ba5e683afa655b17eb6b6c687a657669f772b1a2f78813ea662e8c316c12ea01c604e2e2f9ace5ef281f09c4b6c24c4c4631810f30b5209a433515a628cb5aca0520abee45bbc79e9f9519ffd4ad199b40383cb9718a3e8392d7193f68b1bc251a0b788e74186f121dd5ad31ef6b69d69147ab1841aa5380928fbe11a65ad67af36a0ef80a7fd5edf9901e2d8fa0cd8d9608e9fde114da1bd0f545e107c6771d5b0e7a05e8d9b24b83dbb8ec946cd42ff04bd0588f15866cd95095a8495242616b9ae71a0d623ee5bd0f3b8513ad7c247d1736841878f7210445209cecf36f0bfa5b8a6b9a03d0b62b3dc96b9c72190ff3484699d4892dea93cd16d9811cd58bd614348db11a0b140f98169be15dc1266be9343a1225fe6339f86e309854b03af9d304e75bd76a04ca100367dd9f12a6e80f48a1fabc19d9d36f07960d1911c3a09199a43eb26d2a05e9c627adafc5393a9b5ddc910f6474c56a10366f9d44248d9c0ce2e0c6b9a94a097e533731c36c43d7cf20379f2349ac1cd7a1165fb3588432be8d315801b2e80a0765168ad98f52483060045ae5208451078b2e6876a6f90d40a5c3e3f31cc559ba0479dd4f67d939fa21dd0528703a68c933f8a3d8e504d48f8c9bf7c41e92deecd80",
    "0xf90211a04232cef0e6c4bbd5969f864233a23762543460900e04868931685e0148ae2d10a05353ae18ba63650d7281fefa6fb545b7314cadafd459eed25c7db4915d834e95a022fe8bbf3b304ea8fa6e0cb69c9a3a05cdcf0c3542a5e389a9518177a1925bdca0377ac9d4284000e1f98327783989043f4a6b59d48f5a80579c71adfd880f651ea049da166e0ceb03cf24a2cc03b3bd5e862eddd540a2c517493125322b3a30e85ba0aa9980b3bf84ce0b360f10ca3b230b5dbc9eecba684ed1add96b23167728574ea0f28a3be0e42f13e78f306970fd3a1aac286b30af8af1f460e50eba1d879d61b8a0c84f2fd48976ee7662adc809abb439ea056b3615b622f2938b597782501a4279a0ca13452ffbe75eedde1d870340997ce269c83f6642eefa2d4e9d6bd21c8fc838a0dd918c25e25823548a6a31edb27b65421b2b77063cdc71b13c43eed15b86b924a01a4d8ab05ce030242b59014d96fe1adca52c3f5d13eb09feefbf6eaf97e6fcfba09187e247644a19fe62860dba6e2317f40fe9907c8101bf9e1b04e4b5dadb8ec4a02c299cdc9b87c7f3b1402627f9bcc488d8655a6cbc5d458155024dc8be90ea7aa0373f215d7bc10a74a8e11ddbd3395e27d55cfab62a433b2c6961c1beee9ff3c8a04ec09787d6040119700a0d38154d4a589e1d62245fcd685768cd265cda5ee576a00086a240676e913c0b969397fbc72191719834bc533ba4601406ea062ea76f9b80",
    "0xf90151808080a0ae1018f6569474784bbb933125e397f72f160cb86bf9528ba522e2957e6b27b6a07e10da74c2d11b8dda5b0127b4b39a0d7a1f4a1c9f0dc1a05ae1f3fa3346c86ba0884fa49d5faae435667fe982950ccf82aa58a148dffdb99c5eb7da6b01fd9b00a0065e97ea5d45a492c2aa8eade7534551a04e7899f0bcebeeccc42a1cb2292ce3a0c3a2aae48ed7395cc59065eedd5cb40d9a0cb02db9a9afaccd27efd6282464eb808080a0fc9e1fdc7239d8adc047265bb6589ddefac9a63c1c9829ef2b4717a4b9000dd7a0c285558e316f3ea0ceb2ca5681a79e5d3e3d6d6f21054d5056a6e9ad7dcdd6c7a0de8e2f7f5743997eabe69cb1d99ef0aec670da0b31b466bd8e14d24df17542d6a026ad23a1ed5a6f66a4e6e64fa1b3c37c0878975ba0b8872f5d8ae7c215a0f9c5a0f0ac72c6fc609e78ca13cefea04ef39ff7c9c49198a641508bf7d51bc997239180",
    "0xf851808080808080a0292e7aa7b0fa371f45a26562a180d952f2f3bd3d7a67eb019747b10876cd61a6a0c7f2b75df52f531ca04c4b7c6449bb8be8eae52bf543dfb78383eda4625d922e808080808080808080",
    "0xf8669d37118893aaaf73153bacee2bbd50b8234ab255361cc8614a5713b77282b846f8440180a088219055c2fef8800e02f071d053a86a4194e70a81b6e45f1fecca7dae0432daa01f958654ab06a152993e7a0ae7b6dbb0d4b19265cc9337b8789fe1353bd9dc35"
  ],
  "storageProof": [
    {
      "key": "0x65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08",
      "proof": [
        "0xf901118080a04fc5f13ab2f9ba0c2da88b0151ab0e7cf4d85d08cca45ccd923c6ab76323eb28a09d1f77882a1c2e804de950478b4fdec793decb817e7bbe24a2afd23eb000d648a0f57febb7b16455e051f412a56e54016c676a3d4aa515d2e77a90520dfe36162ea0dce964c738816bb26d659513b793496cac2279d100812e6441aae3f7ffefce2080a0d5223d0cc181c8c0cd1babb8cd0b4d6433eab19a9fcc7836681589aad346556fa0c61ebce1cecbc190ee1163d0ff9ff456cb1fe3409dc546bf2f9118662e6db892a024513ee2bee3b30d4b4e4b600b5a98db38db03f6db556f492d24ac0ff9d6c98fa019bbead828fb8baf57dfda3a30a0b6da048e31faee39f5a76a99b51f28c6c512808080808080",
        "0xf7a031a88f3936348d602f3078126bdcd162c575cb17fb9bbfe2dab00b167bd295c39594715b7219d986641df9efd9c7ef01218d528e19ec"
      ],
      "value": "0x715b7219d986641df9efd9c7ef01218d528e19ec"
    }
  ]
}
`

// Example account result from Sepolia with leading 0 storage key:
// cast proof 0x646ABc71ec777C54d4Ce3a15771804815a458cdF 0x05a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c04 --block 7110607
const resultLeading0Data = `
{
  "address": "0x646abc71ec777c54d4ce3a15771804815a458cdf",
  "balance": "0x0",
  "codeHash": "0x4a052f694c06aa85067c34e533c5bdc98e51d2e01655b34e896d2c9117e277d0",
  "nonce": "0x1",
  "storageHash": "0x5752d84e1773126d65605523ce54905840f3d01272ca8bc2a4502a462575fa8a",
  "accountProof": [
    "0xf90211a0b48cbc8f687f72a4379cb26a5bb727fea6363d01046dbd7532b2cd212fbd26c5a01938009577afb88e5f1cc70ce3ebdacdfc688102908641024ba874ddb2fa9e1ea0236a35af965df43a9d81689323d79018fb6f686517b3472afc62343e894dc731a0b08fe628a3200234c15023375e40a39cab4706cd31454940d2121d2628045a1ba0eec8ba845b13bc1efb72aff556c25ee34cf95cea37e0eb066bc9889353bc92a1a07dcb69e84a672a51e64b7145d13b0c6fc3452a4744e5219483129fbea803d4b2a08513bd3002c6fd1e906625cfdbd337b21e201c36f8bb008f26e0678a28ab7c41a00d714f3c43c66c6fe30479a6090ef207de09752b097dc7bb767b9c6087765cdfa09ac44bf1480233ea5dcc886efb5aa3d3f357dcaf0958be8025fb0d47c466c1d6a0afb37ff0e26a49f5d3ccd984422ef20bd563573fa2bc0cf42de7de1dbfd60eb1a08905951e7440bac5edc94916a7fe65538ec2268f2c727900204792d7c43bec62a0086a2682ddfdb45bf171d3d1f5d809fb90a152a73fb85fa6007ff0dfdf5c5d13a010ee0e01dc72c7a5a7394818f7cf29fbc97c298961cc6dc23664b61ef12bdd36a061beb8fd5604665d26d54d5daa73a19b5729e54568b79f73656e7e6c1a3133fda08573a09bf3cab797013b2d191ff0b52c1825b1817997d1cec5074fbba78f549aa07cf69385fc7ed165f40c2e7140b386f34412e35fadaae51419479202ce73474f80",
    "0xf90211a0164f73d73d1ec7b582a742f72efa878af86b8bfdc23e67630dfffeacfb2ba466a0af73aa0e5aca12f07c2cc046acf4e96491fd1959b4aad12d643820999b206f3fa0d53e1a8a370103183116db747d02c2a51d391eede9dea469c2c8560d766e66b2a0fde1ecff0fc3c37b90dfafd4f48989d178d35d52873f5795b6c67eb9e7034469a03c8e99ce1ab1bbf48888f5b8a28acacee3305a274d3987a5bf36f9d33215d35da0516b671913d82c249c4ab27a606d67e272c80b39decc03c3cbfaf38f4d6b0e8ea07584febfdea40b4f9eaa972d2f6aa6fa5486fe4a3ee3a16bde4772a5b407ec0aa06c56850a7b650c99d967e546b5a9157b3f8a878eac5f5cb26c29c1b00bb7172da003ec0c922b7ab9bff37e26b7ccca68c35d9079d8a9b4c2bf7fff04fc1481bb78a0ababef1089d7b249cc13f729d7d08d7fcb1d23e1e64a77ba7ead64ed76e584e6a011ef584bf1c211bab942556597837a1ee6e104e52abaf70673bbf19a6ef8703fa0e6e591fe5c965c62a325dd3cb204d15c5804ce199d23b224a447cf08695e4c93a0c4a1ca72ae143ab3614ccd7e232bc22b806c3bc0bc7f1e02db5c4f34e6c900faa02e14766aab683fed59060b7314e3360af1c41d235f0e5f918092c476eed228e1a088f86fc092d16286e12830319f222b88bfc7daaf66bda29d5c048de9e0938e24a01af57238eeedbede57f5d415d5f8c1df9dcd3497cef575abb45f48a70db7712580",
    "0xf90211a04dbf32d5e13be1267c8bd8a515fbccd8bc2c427269900d3e15ff6b985521b964a068fb4b17c28b87a287bb09e4476cc735768992dc379170e53fc500be2940d45aa09ba4cc7aee774083b95e2e92dc68d00a3ea65fab1849428d6490dfbb5923ab7ca0cc4fd2f82028ba6118764bcca877609f3ce9fd4cc7eb1566493a67ef6ba005e1a06c2eee84bb227a576f1efe8431ead1f362630a62a89df5953ad65147137aa2d5a0d9bb6d6b0ea2d8434ad62363af08cda05925816d14060f8ef92f5ba8cd34632ba014b6bc02e145aca2896d131d35851402dfe520a958af718a451332334b63fca6a0040af21704fc66ffe12da1b08a737c18887a1ce0f5bd4a76901036c9fe39662ea0ed3b8f4ba2f9a67a4efd835a3faaadb2616302d639bb457687e1fd80f96156b4a052eb144ba84262040f63dcc48db4f3bf9cac3a30aba417a1f096f3f5133aa0cfa007dd950928221eb341bae8f3fb759f3e04df53365d516b9d7cad0b1b7e2c4acca007bd44ff36192b7902aa2e83846bb6a7f9a9496c5fb433bf520c3ebb6cc02300a0f58c1418fed5f9b19ebd8c41fe1426a6eb4176e5a20c4aa7b13f710b3a67f0eda06f1b28517ed359d5e433fe316ee7e0d06ded2cf1e177ebd182d0336eb0b793a7a0de1d0675c8827f775dacd82f5abb7573ed5266ec3cdce086bb205936e5e7f08ea0d9d8664dc55783661a12aa454cc27c893d86e0497b7978d9aecf2d1774b9d4a080",
    "0xf90211a072f47a3df7c02e879796962bc10b9fdc2aebb122b0b191e025e9ed82074ee065a09a46056bb2caf07361718b1eda8c2b0dc40e2a75bd5aa7aeb989e99e6339f6b8a0d224b3ec30f137cdeb227e2b29722589431341e01e5637a1865d8e75f52d88a6a01a74d3693539735a45ab5b3109806c9ad0a09f672fca13133532d64ee231124da0b8b8946deecb061f662a4aa19e93169dd18e85a6a362961ea630b940ca6ec4d2a0ef10a28a659cc296518c5af5c739993ac05563bd3e6488b456b65ed89f26fef0a0849c6f1fabbf5669b2b537041d297fbdc513717776f72635af626c4881523331a035aa294cf2678d3c33ec68932974a40fa593a75a563d2de38ff6242d12eb38d2a00079e9d558815749350860f76439bec10a137be7e7f29d34c95b5ec39f5e07e6a072b3cf10550ed8c8e7b806577e68783b60813e524b0f9c6780a04f6715624a18a047cb5fd0cd0b788b2cd1f812ab263fd35c60b16a5f3c4a752b851d37425d19bca06c3aa866d343bc724be487ac84dd7bfe6d4948119b93b435209d719a336899b1a0e9cfd7d30c58356e264d9964bf3da1be9ede3c19ce2477fc971f0baf703c3083a02b5e0784db3f7b69b4423d1be48b6c0e6722c4f3488716808c2c2c45381c75d2a0ebfb3a1e946faa9fb650b84cb862657ac3779b3a8c3cbe89b1ae0adc342820a1a06df65c62743ca61266a0c9421941019ce767f6ff5a07e53f9d37bb8c9028e2a280",
    "0xf90211a0bd9fd0282403ca2d6cee489cade2e2133f9aa4ad39746bf597d3d9d923e25262a078aca5ee57f708e06135cfffff1f82d4d99898781d4e750e3afe89afc0921499a0f4cfe89fbe5af182e8c48813b8f5dc91e1c03cf6c012b9fdacd1d6ddd03603f9a0c206eece1bfa53d7fdd6ab2ccd1d575d5301bc4843534fc654988147c609492aa0fde0352b4a762f4bdf9b59b22a47db1426d85ad34180bdc1a259ddabdac6b415a016aeaa29b75ff9715cc1fe39e4b93cf6efb11ca065725bb9252a7223774b50f3a047f64b89a97371c6a7b915352238ba09fc225b35ed4408b17a059bd87bfbddd0a072231e4d8968c1e881af398ea93abd5bd4800617614380f3d89f0e13c24b8a64a0ded099761ed89e05f7370614b1cb687a0138291c6c013169f3b266d753af9f29a0b929b7ff8450ae29b8349c633413b632500b814f11abe28a745162d900c14defa03649bcf37a21a155eb38beaf922a08fa10943aed2ea0fe279e04d4ba1961d55ba0d8adc4201cf6ef6b1d40bf800aa96f8f84eade172ba61bafdbf05742842da27ea078f537ed812fe984236f80ead5c24ca9c91cb71f008ef5de7892bde87c03e5eba058f533a1cf09a7d1df17410a5d4ee0685080d52f8417b6dda3aabc8bbe7bb17ea010dd5e2c2037fc42bd7d0c995b58d18907ccfb80656725cafc3538f5667041dda08533ed233a6fbd65b110ca4876ad29c9ad4b09b15d926cdb4d9baa7fa941764380",
    "0xf901f1a0e71f2a795d81a4265151a8806fec284f1c2e123fab6ce18800e63eea72d1468ca0f557fee9b311629a4323c6d5eed533b05bba38efefa9f60cf8ad148e8db21869a07e7682b2f505443124686a25fa3e936912d3ea395d6aa0377eaa7b1082a7328ea0652df178c94950e50355b2c24e530d95758ecbf92bab623860ef4bda714ff895a08a24395656b7ee460281787114ab5ab101d958f9ee9d7872846eb4be42cf7279a0eaa9b7983659ebaf10f66294307606ce1914f507d293a49586f96f1592257cfca01c0db43e7f19e8920fdf8d75ee158347f5ccaa7354ea795a6d2aa97f9e3561a2a0828a855715f0ff05cd2ccd9eb3dc90a6441600f109dd7149b6f46d68b2c889dea0964493b277c84b38fbc3c6cc438d6f56f5913ab9d8d2d63dc3632eb50c88d7d3a027d91f7445a96e9c638acb248ebb2b888f5c85c1246bbd09a0c8f75c074b43ffa08634af715c9f8e0ecec0fe384ded1fdd937f006a3a64ff083f61e4375197ef08a06bedc73cf278c09c4dfadf022a7b9895276dee5742e399667e643bddf6af7eee80a05a42d6b4aa54369f300b633858c16156d798ed2ca56547fed135beea003efef6a0faa502299c593fdc81194de71b7321d752decdcabc6e75784805c76d176897cca072a6dd77969d0c3378044358b6f69054c8dbfbc62ba65bc5b8b28e936c8b281780",
    "0xf851808080808080a043117d8e78c6b71a5ae24ca85c3325a0d5095c1c791d2dcf8cfa0d058dd5a14f8080808080808080a0067fa987d8321740568f1ce21d704641940e2fed21726ecf068080190ec1b02580",
    "0xf8669d3b965179f58d27100724b209b9352cbb7b02ee7cbf4292dc3ed128a445b846f8440180a05752d84e1773126d65605523ce54905840f3d01272ca8bc2a4502a462575fa8aa04a052f694c06aa85067c34e533c5bdc98e51d2e01655b34e896d2c9117e277d0"
  ],
  "storageProof": [
    {
      "key": "0x05a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c04",
      "value": "0x0",
      "proof": [
        "0xf8918080a04fc5f13ab2f9ba0c2da88b0151ab0e7cf4d85d08cca45ccd923c6ab76323eb2880808080a0a3c972be65ae9c04fe77963472d2b5604947836674f3d738214787e766308a60a041c0aaa7c6a0703bae00bc8e8f0d01405be90b03ee9e2511252eb00ea753a80780a02eff96251169d7ba6ff71c7b4c68b0ad184181f68018ec5bc32df2c666c63348808080808080"
      ]
    }
  ]
}
`

// Truncated storage proof key to test unmarshalling.
const invalidResultDataTruncated = `
{
  "address": "0xae851f927ee40de99aabb7461c00f9622ab91d60",
  "balance": "0x0",
  "codeHash": "0x1f958654ab06a152993e7a0ae7b6dbb0d4b19265cc9337b8789fe1353bd9dc35",
  "nonce": "0x1",
  "storageHash": "0x88219055c2fef8800e02f071d053a86a4194e70a81b6e45f1fecca7dae0432da",
  "accountProof": [
    "0xf90211a063a66cd84a54f8ee248662f1d4637936c430a0f455eeec8c01ee56db898dddfba0be9003fb3e36a55cfea1eda010c0a459f10729db9809e0bd1e3599f46c5ffed1a0a08d018d3cf38b0d0cbff14288699705dfa7cf27dc20fbbaae9351837eff4751a0eed877086740a930f035b75ebb26ce63df0f61baea52bf05f4c7421014debf33a053ea34e49423e790b10d9a36f498f337b3f079ed611d98a3f8550c34212dcbd7a0c370d5b874f70b9fd1c8a2fe98b0ef60c480fbe00566a7d5a5e682d9859398f2a0da820e94aac0b444a8dcfebc7dc9ec942f04f252da25b10faf50b57f969aa1f5a0413e8039c67d8acbe20993ab364c2c477d1ce85e8ae723c33acd506175ce4bffa0f70e5d5d934c53b2302ec3f98bd3f33f39a15fabb8c32e5e7acc97121d7a9cf3a0b41e7073ae943e498681b5d86941401c29b38c93fa347ace6bb15ba74ccbf45ea0a3b0aa548cac9cbbfcfabd980c1ceae8bdc39ad2682fc6e6d9cf0f4bdb273884a04d7932870a3d25163ea28ae5ebe702b841d755541d2af98c5c1c08090327fab1a06e41c3fb6362dd860a098aacf13a81c9d26e9b822c1066ca76cb98607f3e257aa0079ffe59ddb21ccd03bcbf1cc42fc0fb89dcae93ffeed9b82a848828199ab057a0dce67e92c8991df57ecac2237244d12e92f6514db1c5f076718fe40266bbf741a08dd7d3b3b041889f837217761b4e87510428ea41b3aff4e5725fd8efc2d735b980",
    "0xf90211a0809683f3310d75dff5eb95296aa9ff5d74fbde9f873b9a6b245513887f9c6e91a055450f5338cc2f8f4306912e938df3fe490929614604eeea4c03581b98c8ae8ea04e50b57da8fc16a5d5460892196631737eeb1cc1e995e5c1de9c381ed1fb84d4a07d65e61a50579d689422446c23df10c4c0b5ec41239a910ca86634e2fee75320a091c77e1f72302bdb3985b249dba07d1abaa345296080c369bd84c518669297e1a019a185bedc83ab48c51dffe4c58ab88e30c88976a3b059ab524ef7ab42886d61a0a6c249e070db991141ee1289a5ed212f81673f8cd3f7bf35c27c335cc77d3eeca0c7d7a7f5036c8c3185cd0ca231775047192419b8f7e7b5a462c8e713ab2f4fcda006084fdd6777d076850defc5c6f1336535bbc2ec95a0e3f91fc5ac9761aee770a0c85a82f527990667217fac36ebfb9f4af29a6ff7b0b3d41cdcb256a26ca5f621a06a382d1f5a9bb0b712c89e82b0aaf26cf7c5984255377fd7428457d390330d40a0194f1f730e71559662ea2d9bdc681761eaf54decc7041766b5d7b7e8086d2480a05afe23c9ec57c22d9639f9228aa389e7a70a4e1e3e675856792f4a92fe284478a05bcacd2d3d2ac267d5b0367b56f05e4c808e2a5ecd04a10f1399e313fd41b273a09e62b6f5b7b77a1657ded9f0bef2af7fee11f2bf0518a5cceb5ceae2845c16f0a06d0ee25c5a3acd2b8d3253b856a77187b76f90d60b2356fc77f6e79766410cc580",
    "0xf90211a0a6b81aae9b8aff6ac275885f6dfa4bc11949e3e8cbfad05714c3233303fa83f5a0e29595c647574b219c3068a768d47347b0e8a272da881aeb4525af051faab847a0441c1549c250c0c1bc0fa1b73e9f9ac9998b5dcef65a57ecd3f748ce02be4251a0353bd042ac0cf9a90a9cc02cc131f5d58f531df8df7ab752f6caa9b6807a506ea07340f489ba55fc8cfde61384c4990f74034f0bc0c7e1d68733284cb5c30d5bbea00ff5d4191ef973be9ae73b3fd9d01f52b54aafa20f147b6a5ca6b9e56a1f9ec4a0e167cd5a249a0dc2afbb9b2aafbd3b6e0160739a99e482d22d722c78fa296772a004202f2695770715d36e9aad418cc005fd8b22b927f1e1383b4e95ca18f41f61a0be38b6340286e0cd2454d90d8ed2f7e26bce5b7774f8adfa8f54a75bc4635d18a0cacc635e487a0d7dd19373bcd0a32e4cea0655f93d61f2940a6063059a044bf7a0bcd8f9ab88356e86cea7cd27454525ade016bccf26f414ad9fa93e0280d40df4a0d5651902739f9dfaff0f1178ea7cba617087234dd0e2895424961fad98605a27a0f76890befb5b3b20695d64b6a7c416709c93032012b46245c5bc00dd104b84f3a00ff372b11e0fb8febd467e060f7ce126e705a07a203a3f6dd93c7e3f36f4608ea0b4ea8133548c9b9d8f62b86aa703f65e3323a92a4b4711f80a734b80814b0825a04db29c4cb760e4831bfe40cdb0f554d74e98da26715c7e6319317c8c9a9c247580",
    "0xf90211a026ffcc82ed6e3cd13ea30ed185afae29eed7f7fbde7f46010061791b5441b7dfa086b3018a2c001ffd6cc76e58372c49f5a2ba42335789fdcea878d93ceeeeb969a0589ba5e683afa655b17eb6b6c687a657669f772b1a2f78813ea662e8c316c12ea01c604e2e2f9ace5ef281f09c4b6c24c4c4631810f30b5209a433515a628cb5aca0520abee45bbc79e9f9519ffd4ad199b40383cb9718a3e8392d7193f68b1bc251a0b788e74186f121dd5ad31ef6b69d69147ab1841aa5380928fbe11a65ad67af36a0ef80a7fd5edf9901e2d8fa0cd8d9608e9fde114da1bd0f545e107c6771d5b0e7a05e8d9b24b83dbb8ec946cd42ff04bd0588f15866cd95095a8495242616b9ae71a0d623ee5bd0f3b8513ad7c247d1736841878f7210445209cecf36f0bfa5b8a6b9a03d0b62b3dc96b9c72190ff3484699d4892dea93cd16d9811cd58bd614348db11a0b140f98169be15dc1266be9343a1225fe6339f86e309854b03af9d304e75bd76a04ca100367dd9f12a6e80f48a1fabc19d9d36f07960d1911c3a09199a43eb26d2a05e9c627adafc5393a9b5ddc910f6474c56a10366f9d44248d9c0ce2e0c6b9a94a097e533731c36c43d7cf20379f2349ac1cd7a1165fb3588432be8d315801b2e80a0765168ad98f52483060045ae5208451078b2e6876a6f90d40a5c3e3f31cc559ba0479dd4f67d939fa21dd0528703a68c933f8a3d8e504d48f8c9bf7c41e92deecd80",
    "0xf90211a04232cef0e6c4bbd5969f864233a23762543460900e04868931685e0148ae2d10a05353ae18ba63650d7281fefa6fb545b7314cadafd459eed25c7db4915d834e95a022fe8bbf3b304ea8fa6e0cb69c9a3a05cdcf0c3542a5e389a9518177a1925bdca0377ac9d4284000e1f98327783989043f4a6b59d48f5a80579c71adfd880f651ea049da166e0ceb03cf24a2cc03b3bd5e862eddd540a2c517493125322b3a30e85ba0aa9980b3bf84ce0b360f10ca3b230b5dbc9eecba684ed1add96b23167728574ea0f28a3be0e42f13e78f306970fd3a1aac286b30af8af1f460e50eba1d879d61b8a0c84f2fd48976ee7662adc809abb439ea056b3615b622f2938b597782501a4279a0ca13452ffbe75eedde1d870340997ce269c83f6642eefa2d4e9d6bd21c8fc838a0dd918c25e25823548a6a31edb27b65421b2b77063cdc71b13c43eed15b86b924a01a4d8ab05ce030242b59014d96fe1adca52c3f5d13eb09feefbf6eaf97e6fcfba09187e247644a19fe62860dba6e2317f40fe9907c8101bf9e1b04e4b5dadb8ec4a02c299cdc9b87c7f3b1402627f9bcc488d8655a6cbc5d458155024dc8be90ea7aa0373f215d7bc10a74a8e11ddbd3395e27d55cfab62a433b2c6961c1beee9ff3c8a04ec09787d6040119700a0d38154d4a589e1d62245fcd685768cd265cda5ee576a00086a240676e913c0b969397fbc72191719834bc533ba4601406ea062ea76f9b80",
    "0xf90151808080a0ae1018f6569474784bbb933125e397f72f160cb86bf9528ba522e2957e6b27b6a07e10da74c2d11b8dda5b0127b4b39a0d7a1f4a1c9f0dc1a05ae1f3fa3346c86ba0884fa49d5faae435667fe982950ccf82aa58a148dffdb99c5eb7da6b01fd9b00a0065e97ea5d45a492c2aa8eade7534551a04e7899f0bcebeeccc42a1cb2292ce3a0c3a2aae48ed7395cc59065eedd5cb40d9a0cb02db9a9afaccd27efd6282464eb808080a0fc9e1fdc7239d8adc047265bb6589ddefac9a63c1c9829ef2b4717a4b9000dd7a0c285558e316f3ea0ceb2ca5681a79e5d3e3d6d6f21054d5056a6e9ad7dcdd6c7a0de8e2f7f5743997eabe69cb1d99ef0aec670da0b31b466bd8e14d24df17542d6a026ad23a1ed5a6f66a4e6e64fa1b3c37c0878975ba0b8872f5d8ae7c215a0f9c5a0f0ac72c6fc609e78ca13cefea04ef39ff7c9c49198a641508bf7d51bc997239180",
    "0xf851808080808080a0292e7aa7b0fa371f45a26562a180d952f2f3bd3d7a67eb019747b10876cd61a6a0c7f2b75df52f531ca04c4b7c6449bb8be8eae52bf543dfb78383eda4625d922e808080808080808080",
    "0xf8669d37118893aaaf73153bacee2bbd50b8234ab255361cc8614a5713b77282b846f8440180a088219055c2fef8800e02f071d053a86a4194e70a81b6e45f1fecca7dae0432daa01f958654ab06a152993e7a0ae7b6dbb0d4b19265cc9337b8789fe1353bd9dc35"
  ],
  "storageProof": [
    {
      "key": "0x0",
      "proof": [
        "0xf901118080a04fc5f13ab2f9ba0c2da88b0151ab0e7cf4d85d08cca45ccd923c6ab76323eb28a09d1f77882a1c2e804de950478b4fdec793decb817e7bbe24a2afd23eb000d648a0f57febb7b16455e051f412a56e54016c676a3d4aa515d2e77a90520dfe36162ea0dce964c738816bb26d659513b793496cac2279d100812e6441aae3f7ffefce2080a0d5223d0cc181c8c0cd1babb8cd0b4d6433eab19a9fcc7836681589aad346556fa0c61ebce1cecbc190ee1163d0ff9ff456cb1fe3409dc546bf2f9118662e6db892a024513ee2bee3b30d4b4e4b600b5a98db38db03f6db556f492d24ac0ff9d6c98fa019bbead828fb8baf57dfda3a30a0b6da048e31faee39f5a76a99b51f28c6c512808080808080",
        "0xf7a031a88f3936348d602f3078126bdcd162c575cb17fb9bbfe2dab00b167bd295c39594715b7219d986641df9efd9c7ef01218d528e19ec"
      ],
      "value": "0x715b7219d986641df9efd9c7ef01218d528e19ec"
    }
  ]
}
`

var goodRoot = common.HexToHash("0x070ef87d6d3a8a132dfb45cbbc86daf545a45f1a0263bd28a304e465327f3557")

func TestAccountResult_Verify(t *testing.T) {
	result := makeResult(t)
	require.NoError(t, result.Verify(goodRoot), "verifies against good state root")
	require.NotNil(t, result.Verify(common.HexToHash("0x070ef87d6d3a8a132dfb45cbbc86daf545a45f1a0263bd28a304e465327f3558")), "does not verify against other state root")
	result = makeResult(t)
	result.StorageProof[0].Proof[0][0] = 0x00
	require.NotNil(t, result.Verify(goodRoot), "does not verify against bad proof")
	result = makeResult(t)
	result.AccountProof[0][0] = 0x00
	require.NotNil(t, result.Verify(goodRoot), "does not verify against bad proof")
}

func TestAccountResult_MarshalTruncated(t *testing.T) {
	var result AccountResult
	require.NoError(t, json.Unmarshal([]byte(invalidResultDataTruncated), &result))
}

func FuzzAccountResult_StorageProof(f *testing.F) {
	// from the makeResult function, the known proof:
	knownValidkey := common.HexToHash("0x65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08")
	knownValidValue := common.FromHex("0x715b7219d986641df9efd9c7ef01218d528e19ec")
	f.Add(knownValidkey[:], knownValidValue[:])
	f.Fuzz(func(t *testing.T, key []byte, value []byte) {
		result := makeResult(t)
		result.StorageProof[0].Key = key
		result.StorageProof[0].Value = hexutil.Big(*(new(big.Int).SetBytes(value)))
		err := result.Verify(goodRoot)
		if bytes.Equal(key, knownValidkey[:]) {
			if bytes.Equal(value, knownValidValue) {
				require.NoError(t, err, "known key/value pair must pass")
			} else {
				require.Errorf(t, err, "other values for known key must fail, but got 0x%x", value)
			}
		} else {
			if bigs.IsZero(result.StorageProof[0].Value.ToInt()) {
				// When there's a valid trie, and we proof exclusion (i.e. non-existent key turns into a 0 value),
				// then `trie.VerifyProof` will simply not error when given the valid storage-proof that
				// shows some valid adjacent path that implies the exclusion of the actual value at the queried key path.
				if err != nil {
					// missing proof nodes can happen, exclusion proofs by showing the known value won't always be deep enough
					require.ErrorContains(t, err, "missing")
				}
			} else {
				require.Errorf(t, err, "random other key/value pairs (key=0x%x value=0x%x) should not verify", key, value)
			}
		}
	})
}

func FuzzAccountResult_AccountProof(f *testing.F) {
	f.Fuzz(func(t *testing.T, address []byte, balance []byte, codeHash []byte, nonce uint64, storageHash []byte) {
		result := makeResult(t)
		result.Address = common.BytesToAddress(address)
		bal := hexutil.Big(*new(big.Int).SetBytes(balance))
		result.Balance = &bal
		result.CodeHash = common.BytesToHash(codeHash)
		result.Nonce = hexutil.Uint64(nonce)
		result.StorageHash = common.BytesToHash(storageHash)
		require.NotNil(t, result.Verify(goodRoot), "does not verify against bad account proof")
	})
}

func makeResult(t *testing.T) AccountResult {
	var result AccountResult
	require.NoError(t, json.Unmarshal([]byte(resultData), &result))
	return result
}

func TestLeading0Key(t *testing.T) {
	var result AccountResult
	require.NoError(t, json.Unmarshal([]byte(resultLeading0Data), &result))
}
